/*****************************************************************************
Copyright 2006 Kervin L. Pierre
    EMAIL: otlkcon@adevsoft.com

This file is part of Otlkcon.

Otlkcon is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

Otlkcon is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Lesser GNU General Public License for more details.

You should have received a copy of the Lesser GNU General Public License
along with Otlkcon; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*******************************************************************************/

#pragma once

#include "StdAfx.h"
#include "otlkcon_compare_props.h"
#include "O_IProp.h"
#include <sqlite/sqlite3.h>

#include <algorithm>
#include <vector>
#include <list>

using namespace std;

class otlkcon_generic_msgstore;
class O_ITable;

class O_ITableAdviseSink : public IMAPIAdviseSink
{
public:
    MAPI_IUNKNOWN_METHODS(IMPL);
    MAPI_IMAPIADVISESINK_METHODS(IMPL);

    O_ITableAdviseSink( O_ITable *tbl );
    ~O_ITableAdviseSink();

    O_ITable *table;

    ULONG cRef;
};

//! The OpenConnector implementation of MAPI's IMAPITable interface. 

//! O_ITable class is an implementation of the IMAPITable interface.
//! Please see the MAPI interface documentation for information on
//! IMAPITable methods.  Here we only describe the features specific
//! to the O_ITable class.
#define UPDATE_SNAPSHOT_ONLY	(ULONG)1
#define UPDATE_TABLE_ONLY		(ULONG)2

class O_ITable : IMAPITable
{
public:
    MAPI_IUNKNOWN_METHODS(IMPL);

    //! Documented in MAPI interface documentation
    STDMETHODIMP GetLastError (HRESULT hResult,
        ULONG ulFlags,
        LPMAPIERROR * lppMAPIError);

    //! Documented in MAPI interface documentation
    STDMETHODIMP Advise (ULONG ulEventMask,
        LPMAPIADVISESINK lpAdviseSink,
        ULONG * lpulConnection);

    //! Documented in MAPI interface documentation
    STDMETHODIMP Unadvise (ULONG ulConnection);

    //! Documented in MAPI interface documentation
    STDMETHODIMP GetStatus (ULONG * lpulTableStatus,
        ULONG * lpulTableType);

    //! Documented in MAPI interface documentation
    STDMETHODIMP SetColumns (LPSPropTagArray lpPropTagArray,
        ULONG ulFlags);

    //! Documented in MAPI interface documentation
    STDMETHODIMP QueryColumns (ULONG ulFlags,
        LPSPropTagArray * lpPropTagArray);

    //! Documented in MAPI interface documentation
    STDMETHODIMP GetRowCount (ULONG ulFlags,
        ULONG * lpulCount);

    //! Documented in MAPI interface documentation
    STDMETHODIMP SeekRow (BOOKMARK bkOrigin,
        LONG lRowCount,
        LONG * lplRowsSought);

    //! Documented in MAPI interface documentation
    STDMETHODIMP SeekRowApprox (ULONG ulNumerator,
        ULONG ulDenominator);

    //! Documented in MAPI interface documentation
    STDMETHODIMP QueryPosition (ULONG * lpulRow,
        ULONG * lpulNumerator,
        ULONG * lpulDenominator);

    //! Documented in MAPI interface documentation
    STDMETHODIMP FindRow (LPSRestriction lpRestriction,
        BOOKMARK bkOrigin,
        ULONG ulFlags);

    //! Documented in MAPI interface documentation
    STDMETHODIMP Restrict (LPSRestriction lpRestriction,
        ULONG ulFlags);

    //! Documented in MAPI interface documentation
    STDMETHODIMP CreateBookmark (BOOKMARK * lpbkPosition);

    //! Documented in MAPI interface documentation
    STDMETHODIMP FreeBookmark (BOOKMARK bkPosition);

    //! Documented in MAPI interface documentation
    STDMETHODIMP SortTable (LPSSortOrderSet lpSortCriteria,
        ULONG ulFlags);

    //! Documented in MAPI interface documentation
    STDMETHODIMP QuerySortOrder (LPSSortOrderSet * lppSortCriteria);

    //! Documented in MAPI interface documentation
    STDMETHODIMP QueryRows(LONG lRowCount,
        ULONG ulFlags,
        LPSRowSet * lppRows);

    //! Documented in MAPI interface documentation
    STDMETHODIMP Abort();

    //! Documented in MAPI interface documentation
    STDMETHODIMP ExpandRow (ULONG cbInstanceKey,
        LPBYTE pbInstanceKey,
        ULONG ulRowCount,
        ULONG ulFlags,
        LPSRowSet * lppRows,
        ULONG * lpulMoreRows);

    //! Documented in MAPI interface documentation
    STDMETHODIMP CollapseRow (ULONG cbInstanceKey,
        LPBYTE pbInstanceKey,
        ULONG ulFlags,
        ULONG * lpulRowCount);

    //! Documented in MAPI interface documentation
    STDMETHODIMP WaitForCompletion (ULONG ulFlags,
        ULONG ulTimeout,
        ULONG * lpulTableStatus);

    //! Documented in MAPI interface documentation
    STDMETHODIMP GetCollapseState (ULONG ulFlags,
        ULONG cbInstanceKey,
        LPBYTE lpbInstanceKey,
        ULONG * lpcbCollapseState,
        LPBYTE * lppbCollapseState);

    //! Documented in MAPI interface documentation
    STDMETHODIMP SetCollapseState (ULONG ulFlags,
        ULONG cbCollapseState,
        LPBYTE pbCollapseState,
        BOOKMARK * lpbkLocation);

    //! The O_ITable Constructor
    
    //! Like most constructors in this project, the O_ITable constructor
    //! simply sets default properties.  Object initialization is handled
    //! in the Create() method.
    //! \sa Create()
    O_ITable(void);

    //! The O_ITable Destructor

    //! This function has not been developed yet.
    ~O_ITable(void);

    //! Destroy function resets an object.

    //! This function has not been developed yet.  The goal
    //! is to have this function prepare and object for either
    //! destruction or reinitialization.
    void Destroy();

    //! Creates a new instance of the O_ITable class.

    //! Create is called after the constructor to create a new
    //! instance of the O_ITable class.  Any resources that are
    //! needed for the table are constructed at that time.  Any
    //! MAPI initialization that is manatory is done here.
    //! \param df The file path of the SQLite database.
    //! \param defaultTags The column set of this table.
    //! \param indexTag The column that will be the index value of the table.
    //! \param ig A unique identifier for our table.  A 128 bit number basically.
    //! \param lb Memory allocator function.
    //! \param lm Memory allocator function.  Chains the allocated memory to parent.
    //! \param lf Memory deallocator function.
    //! \sa Load(), Init()
    HRESULT Create( char *df, LPSPropTagArray defaultTags, ULONG indexTag, MAPIUID ig, 
                        otlkcon_generic_msgstore *mstore);

    //! Loads a previously created table into memory.

    //! This function loads an table object that was previously created
    //! using the Create() function.  Create initializes and serializes
    //! a wide range of functions to disk in our database.  Load assumes
    //! that the object had already been previously created and only loads
    //! the needed variables into memory.  There either Create() or Load()
    //! is called after the table constructor, but NOT both
    //! \param df The file path of the SQLite database.
    //! \param tableID This is the table's name in the database.  It comprises of the class type UID and object's UID.
    //! \param lb Memory allocator function.
    //! \param lm Memory allocator function.  Chains the allocated memory to parent.
    //! \param lf Memory deallocator function.
    //! \sa Create(), Init()
    HRESULT Load(char *df, char *tableID, otlkcon_generic_msgstore *mstore);

    //! Initialization function for the table class

    //! This function comprises of basically the actions that need to be
    //! done by both Create() and Load().
    //! \param defaultTags List of columns in the loaded table.
    //! \sa Create(), Load()
    HRESULT Init( LPSPropTagArray defaultTags );

    //! Duplicate the table object

    //! This is done so that we can return a clone to a calling
    //! method that may deallocate the object that it receives.
    HRESULT Duplicate( O_ITable **tbl );

    //! Print the contents of this object to the screen

    //! Dump uses the smlog library.  This library multiplexes
    //! the text output to the debug output window and text
    //! files for example.  The output is in XML format.
    //! \param flag Misc flags.  Eg. whether to print an XML root tag or not.
    STDMETHODIMP Dump( ULONG flag ); 

#ifdef OTLKCON_TEST_O_ITABLE
    //! Test routine for debugging/testing table methods
    STDMETHODIMP Test(char *df, 
                    LPALLOCATEBUFFER lb, LPALLOCATEMORE lm , LPFREEBUFFER lf);
#endif // OTLKCON_TEST_O_ITABLE


    //! Add or modify a table row in this object.

    //! Documented in the ITableData interface documentation in the MAPI manual.
    //! If the row is found in this table, it is replaced.  If it is not found,
    //! then it is added.
    //! \param lpSRow The row to add/replace in the table
    STDMETHODIMP HrModifyRow(LPSRow lpSRow);

    //! Delete a table row in this object.

    //! Documented in the ITableData interface documentation in the MAPI manual.
    //! Simply deletes a row in an object.  It finds the index row in the property
    //! list that it receives, and deletes the row with the corresponding index.
    //! \param lpSPropValue Property set containing an index value.
    STDMETHODIMP HrDeleteRow(LPSPropValue lpSPropValue);
	
	//! Documented in the ITableData interface documentation in the MAPI manual.
	//! Simply deletes a row by row via HrDeleteRow.
	//! Optimized for deleting all rows.
	//! \param ulFlags flags can be TAD_ALL_ROWS for deleting all rows
	//! \param lpRowsetToDelete contains rows to be deleted
	//! \param cRowsDeleted returns count of deleted rows
	STDMETHODIMP HrDeleteRows(ULONG ulFlags,  LPSRowSet lpRowsetToDelete,  ULONG FAR * cRowsDeleted);

    //! Returns a 'view' object of the table.

    //! Documented in the ITableData interface documentation in the MAPI manual.
    //! Table view objects are very similar to table objects.  The share the
    //! same Advice() code.  They may be passed to functions that expect a
    //! reference to the 'main' table objeect.
    STDMETHODIMP HrGetView( LPSSortOrderSet lpSSortOrderSet, 
                            CALLERRELEASE *lpfCallerRelease, ULONG ulCallerData,
                            LPMAPITABLE *lppMAPITable );


	//! Retrieves necessary properties from lpObject
	//! and adds or modifies correspondent row
	//! \param ulFlags Pass UPDATE_SNAPSHOT_ONLY to modify only memory copy
	//! \param lpObject The object to add/modify in the table
	STDMETHODIMP HrUpdateObjectRow(ULONG ulFlags, O_IProp *lpObject);

    //STDMETHODIMP CompactRows();

    /*
    STDMETHODIMP O_ITable::QueryMoreRows(LONG lRowCount,
        ULONG ulFlags,
        LPSRowSet * lppRows );*/

	STDMETHODIMP GetColumnSet(LPSPropTagArray *lppTags);
	
	
	//! Retrieves snapshot of table
	//! It is used to in the transacted objects like IMessage
	//! As transacted objects need a new object 
	//! for every client call we can use this function to retrieve
	//! pointer to underlined ITableData object
	//! So we can modify data directly without modifying permanent storage
	STDMETHODIMP GetSnapShot(LPTABLEDATA* lppTable);
	
	
	//! Subscribes for notification
	//! It is used internally to subscribe synchronously
	STDMETHODIMP InternalAdvise (
		ULONG				ulEventMask,
		LPMAPIADVISESINK	lpAdviseSink,
		ULONG				ulFlags,
		ULONG *				lpulConnection);

    //! The this object's SQL table name in the database

    //! This is name is basically 2 UID stitched together.  The first UID is
    //! that of the type, ie. O_ITable class UID.  The second is unique to each
    //! table object
    char * tableName;

    //! Just a name used for debugging.

    //! Should not be included in the release build
    char * objName;

private:

    otlkcon_generic_msgstore *msgstore;
	typedef set<ULONG> TagSet;


    // Gets a specified row in the table object
	//We using not null tag set from FindRow method
    STDMETHODIMP GetRowAt(ULONG rowNum, LPSRow *lppRow, TagSet *lpTagSet = NULL);

    // Sets a specified row in the table object.
    STDMETHODIMP SetRowAt(ULONG rowNum, LPSRow lpSRow);

    // Finds a row's row number in the table
    STDMETHODIMP _IntFindRow(LPSRow lpSRow, int *rowNum);
    STDMETHODIMP _IntFindRow(LPSPropValue index, int *rowNum);

    // The 'do.*Restriction' functions parse MAPI restriction
    // structures.  See the MAPI 'IMAPITable::Restrict()' documentation
    // for more information.
    STDMETHODIMP doAndRestriction( LPSRow row, SAndRestriction res, BOOL *vis);
    STDMETHODIMP doBitmaskRestriction( LPSRow row, 
        SBitMaskRestriction res, BOOL *vis);
    STDMETHODIMP doCommentRestriction( LPSRow row, 
        SCommentRestriction res, BOOL *vis);
    STDMETHODIMP doComparePropsRestriction( LPSRow row, 
        SComparePropsRestriction res, BOOL *vis);
    STDMETHODIMP doContentRestriction( LPSRow row, 
        SContentRestriction restriction, BOOL *vis);
    STDMETHODIMP doExistRestriction( LPSRow row, 
        SExistRestriction restriction, BOOL *vis);
    STDMETHODIMP doNotRestriction( LPSRow row, 
        SNotRestriction restriction, BOOL *vis);
    STDMETHODIMP doOrRestriction( LPSRow row, SOrRestriction res, BOOL *vis);
    STDMETHODIMP doPropertyRestriction( LPSRow row, 
        SPropertyRestriction res, BOOL *vis);
    STDMETHODIMP doSizeRestriction( LPSRow row, SSizeRestriction res, BOOL *vis);
    STDMETHODIMP doSubRestriction( LPSRow row, SSubRestriction res, BOOL *vis);
    STDMETHODIMP doRestriction( LPSRow row, LPSRestriction restriction, BOOL *vis);

	//calculates all tags needed to check restriction
	STDMETHODIMP calculateTags(LPSRestriction restriction, TagSet &tagSet);
    // Scan's a table row structure for the specified column's value
    HRESULT FindPropInRow(LPSRow row, ULONG propTag, LPSPropValue *propVal);

    // Set's this object's last error value
    HRESULT SetLastError(HRESULT errID, char *errStr);

    // SQLite has a restriction that a databse's handle has to
    // be re-opened on every thread that it is used.  This object
    // Checks that trhead-local-storage has a handle that has been
    // initialized on the current thread.
    STDMETHODIMP_(otlkcon_sqlite_helper *) GetSqlObj();

    // When called, signals any listeners on this object, that an
    // event has occurred.  See Advice()
    HRESULT O_ITable::Notify( O_ENTRYID *key, ULONG cNotification,
        LPNOTIFICATION lpNotifications, ULONG *lpulFlags );

    // data members
    ULONG cRef;

    // The SQLite database file
    char *databaseFilename;

    // For Debugging purposes
    char * className; 

    // The SQLite database wrapper object
	//Henry 30.12.2005: sqlObj should be local variable
//    otlkcon_sqlite_helper *sqlObj;

    // memory functions wrapper object
    otlkcon_memory *memObj;

    //For GetLastError
    int   lastCalledFunctionID;
    char  lastCalledFunctionName[OTLKCON_GETLASTERROR_FUNCTION_NAME_SIZE];
    HRESULT   lastErrorMsgID;
    char  lastErrorMsg[OTLKCON_GETLASTERROR_MSG_SIZE];

    CRITICAL_SECTION objectCS;

    // variable stores the current line the next object
    // method call will use.
    long int  cursor;

    public:
    
    // serialized as row_id = 0
    // This vector has the current column set this object
    // shows.  The current column set can be altered using
    // SetColumns()
    vector<long> currentColumns; 
    
    // serialized as row_id = -1
    // This vector has the original column set defined when
    // this object was created using Create().  This set is
    // never altered except for the addition of new columns
    // which are done by replacing PR_NULL columns with new
    // values using SetColumns()
    vector<long> defaultColumns;

    // The rows, listed by numbers in the current view
    vector<int> currentRows;

    // All the rows in the default view
    vector<int> defaultRows;

    // The list of bookmarks on this object.
    // See CreateBookmark() function.
    vector<BOOKMARK> bookmarks;

    // The current restriction on this object.
    // This restrict affects or pretty much defines
    // the current view.
    LPSRestriction  currentRestriction;

    // The current sort order of the table.
    LPSSortOrderSet currentSortOrder;

    // The column that is our index
    ULONG indexPropTag;

    // Flag indicating whether this object has been
    // initialized yet, usually this is done via the
    // Init() function call.
    bool initialized;

    // A shadow table object
    // FIXME: We should alleviate the need for this.
    LPTABLEDATA lpTblData;

    ULONG derefAssocObj;

    ULONG objectCreateConnection;
    LPMAPIADVISESINK adviseSink;
};
